using SPI.AgentServer.Services.Execution;
using System.Text;
using System.Globalization;

namespace SPI.AgentServer.Services.Tools;

/// <summary>
/// 门禁进出查询工具 - 基于闸机记录表（按月分表）
/// 支持图书馆、宿舍、校门等不同类型闸机的查询，支持聚合统计
/// </summary>
public class GetLibraryAccessTool : IQueryTool
{
    private readonly IDatabaseExecutor _executor;
    private readonly ILogger<GetLibraryAccessTool> _logger;

    public string Name => "get_library_access";
    public string Description => "【重要】查询门禁进出记录（图书馆、宿舍、校门等），基于闸机分表tblgateinformation。支持详细记录和聚合统计两种模式。用于回答'谁进了图书馆'、'统计反复进出宿舍超过5次的学生'、'宿舍进出记录'、'图书馆访问统计'等所有门禁相关问题。优先使用此工具而不是execute_sql！";

    public GetLibraryAccessTool(
        IDatabaseExecutor executor,
        ILogger<GetLibraryAccessTool> logger)
    {
        _executor = executor;
        _logger = logger;
    }

    public async Task<ToolResult> ExecuteAsync(Dictionary<string, object> parameters, CancellationToken cancellationToken = default)
    {
        if (!ValidateParameters(parameters, out var errors))
        {
            return new ToolResult
            {
                Success = false,
                Errors = errors
            };
        }

        try
        {
            _logger.LogInformation("收到参数：{Parameters}", 
                string.Join(", ", parameters.Select(p => $"{p.Key}={p.Value}")));
            
            // 获取时间范围参数
            DateTime startTime;
            DateTime endTime;
            bool hasExplicitStartTime = false;
            bool hasExplicitEndTime = false;
            
            // 获取月份参数（可选）
            DateTime queryMonth = DateTime.Now;
            if (parameters.ContainsKey("month") && parameters["month"] != null)
            {
                var monthStr = parameters["month"].ToString();
                if (!string.IsNullOrEmpty(monthStr))
                {
                    if (DateTime.TryParse(monthStr, out var parsedMonth))
                    {
                        queryMonth = parsedMonth;
                    }
                    else if (DateTime.TryParseExact(monthStr, "yyyy-MM", CultureInfo.InvariantCulture, DateTimeStyles.None, out parsedMonth))
                    {
                        queryMonth = parsedMonth;
                    }
                }
            }

            // 处理开始时间
            if (parameters.ContainsKey("startTime") && parameters["startTime"] != null)
            {
                var startTimeStr = parameters["startTime"].ToString();
                if (!string.IsNullOrEmpty(startTimeStr) && DateTime.TryParse(startTimeStr, out startTime))
                {
                    hasExplicitStartTime = true;
                }
                else
                {
                    startTime = new DateTime(queryMonth.Year, queryMonth.Month, 1, 0, 0, 0);
                }
            }
            else
            {
                // 默认查询当前月份的第一天
                startTime = new DateTime(queryMonth.Year, queryMonth.Month, 1, 0, 0, 0);
            }

            // 处理结束时间
            if (parameters.ContainsKey("endTime") && parameters["endTime"] != null)
            {
                var endTimeStr = parameters["endTime"].ToString();
                if (!string.IsNullOrEmpty(endTimeStr) && DateTime.TryParse(endTimeStr, out endTime))
                {
                    hasExplicitEndTime = true;
                }
                else
                {
                    endTime = startTime.AddMonths(1).AddSeconds(-1);
                }
            }
            else
            {
                // 如果没有显式指定结束时间
                if (hasExplicitStartTime)
                {
                    // 如果只指定了开始时间，结束时间默认为当前时间
                    endTime = DateTime.Now;
                }
                else
                {
                    // 如果都没指定，查询整个月
                    endTime = startTime.AddMonths(1).AddSeconds(-1);
                }
            }
            
            _logger.LogInformation("计算后的时间范围：{StartTime} 至 {EndTime}", 
                startTime.ToString("yyyy-MM-dd HH:mm:ss"), 
                endTime.ToString("yyyy-MM-dd HH:mm:ss"));

            // 获取其他筛选参数
            string? studentId = parameters.ContainsKey("studentId") ? parameters["studentId"]?.ToString() : null;
            string? studentName = parameters.ContainsKey("studentName") ? parameters["studentName"]?.ToString() : null;
            
            // 闸机类型：1=校门口，2=学生公寓/宿舍，3=图书馆，4=办公区
            int gateType = parameters.ContainsKey("gateType") ? Convert.ToInt32(parameters["gateType"]) : 3;
            
            // 是否聚合统计（GROUP BY）
            bool aggregateStats = parameters.ContainsKey("aggregateStats") && Convert.ToBoolean(parameters["aggregateStats"]);
            
            // 最小次数阈值（用于 HAVING 子句）
            int? minCount = parameters.ContainsKey("minCount") ? Convert.ToInt32(parameters["minCount"]) : null;

            // 生成表名后缀（格式：YYYYMM01）
            string tableSuffix = startTime.ToString("yyyyMM01");
            
            // 检查是否跨月查询
            if (startTime.Month != endTime.Month || startTime.Year != endTime.Year)
            {
                // 如果跨月，暂时只查询开始月份的数据（未来可以扩展为UNION多表）
                _logger.LogWarning("查询跨越多个月份，当前只查询起始月份 {Month} 的数据", startTime.ToString("yyyy-MM"));
            }

            // 构建SQL查询
            var sql = aggregateStats 
                ? BuildAggregateQuery(tableSuffix, startTime, endTime, gateType, minCount, studentId, studentName)
                : BuildDetailQuery(tableSuffix, startTime, endTime, gateType, studentId, studentName);

            var gateTypeName = gateType switch
            {
                1 => "校门口",
                2 => "宿舍",
                3 => "图书馆",
                4 => "办公区",
                _ => "未知"
            };

            _logger.LogInformation("Executing {GateType} access query for {StartTime} to {EndTime}, aggregate={Aggregate}", 
                gateTypeName, startTime, endTime, aggregateStats);

            var result = await _executor.ExecuteQueryAsync(sql, null, cancellationToken);

            var message = aggregateStats 
                ? $"{gateTypeName}进出统计查询成功" 
                : $"{gateTypeName}进出记录查询成功";

            return new ToolResult
            {
                Success = true,
                Data = result.Data,
                Message = $"{message}（{startTime:yyyy-MM-dd HH:mm} - {endTime:yyyy-MM-dd HH:mm}）",
                Metadata = new Dictionary<string, object>
                {
                    ["executionTimeMs"] = result.ExecutionTimeMs,
                    ["executedSql"] = sql,
                    ["tableSuffix"] = tableSuffix,
                    ["timeRange"] = $"{startTime:yyyy-MM-dd HH:mm:ss} 至 {endTime:yyyy-MM-dd HH:mm:ss}"
                }
            };
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error executing library access query");
            return new ToolResult
            {
                Success = false,
                Errors = new List<string> { $"查询错误: {ex.Message}" }
            };
        }
    }

    public bool ValidateParameters(Dictionary<string, object> parameters, out List<string> errors)
    {
        errors = new List<string>();
        
        // 月份参数验证
        if (parameters.ContainsKey("month") && parameters["month"] != null)
        {
            var monthStr = parameters["month"].ToString();
            if (!string.IsNullOrEmpty(monthStr))
            {
                if (!DateTime.TryParse(monthStr, out _) && 
                    !DateTime.TryParseExact(monthStr, "yyyy-MM", CultureInfo.InvariantCulture, DateTimeStyles.None, out _))
                {
                    errors.Add("月份格式不正确，请使用 'yyyy-MM' 或完整日期格式");
                    return false;
                }
            }
        }
        
        // 时间参数都是可选的，如果提供则验证格式
        if (parameters.ContainsKey("startTime") && parameters["startTime"] != null)
        {
            var startTimeStr = parameters["startTime"].ToString();
            if (!string.IsNullOrEmpty(startTimeStr) && !DateTime.TryParse(startTimeStr, out _))
            {
                errors.Add("开始时间格式不正确，请使用标准日期时间格式");
                return false;
            }
        }
        
        if (parameters.ContainsKey("endTime") && parameters["endTime"] != null)
        {
            var endTimeStr = parameters["endTime"].ToString();
            if (!string.IsNullOrEmpty(endTimeStr) && !DateTime.TryParse(endTimeStr, out _))
            {
                errors.Add("结束时间格式不正确，请使用标准日期时间格式");
                return false;
            }
        }
        
        return true;
    }

    /// <summary>
    /// 构建详细查询SQL（返回每条进出记录）
    /// </summary>
    private string BuildDetailQuery(string tableSuffix, DateTime startTime, DateTime endTime, int gateType, string? studentId, string? studentName)
    {
        var sb = new StringBuilder();

        sb.AppendLine("SELECT");
        sb.AppendLine("    t1.XGH AS '学工号',");
        sb.AppendLine("    t1.XM AS '姓名',");
        sb.AppendLine("    DATE_FORMAT(t1.SJ, '%Y-%m-%d %H:%i:%s') AS '进入时间',");
        sb.AppendLine("    t1.ZJMC AS '闸机名称',");
        sb.AppendLine("    t1.XQMC AS '校区名称',");
        sb.AppendLine("    t1.CRBS AS '出入标识',");
        sb.AppendLine("    t2.GateLocation AS '闸机位置',");
        sb.AppendLine("    CASE t2.GateType");
        sb.AppendLine("        WHEN 1 THEN '校门口'");
        sb.AppendLine("        WHEN 2 THEN '学生公寓'");
        sb.AppendLine("        WHEN 3 THEN '图书馆'");
        sb.AppendLine("        WHEN 4 THEN '办公区'");
        sb.AppendLine("        ELSE '未知'");
        sb.AppendLine("    END AS '闸机类型'");
        sb.AppendLine($"FROM tblgateinformation_{tableSuffix} t1");
        sb.AppendLine("LEFT JOIN TblGateDetail t2");
        sb.AppendLine("    ON t1.ZJID = t2.GateCode");
        sb.AppendLine($"WHERE t2.GateType = {gateType}  -- 闸机类型");
        
        // 时间范围条件
        sb.AppendLine($"  AND t1.SJ >= '{startTime:yyyy-MM-dd HH:mm:ss}'  -- 开始时间");
        sb.AppendLine($"  AND t1.SJ < '{endTime:yyyy-MM-dd HH:mm:ss}'  -- 结束时间");
        
        // 可选筛选条件
        if (!string.IsNullOrEmpty(studentId))
        {
            sb.AppendLine($"  AND t1.XGH = '{studentId}'  -- 学工号");
        }
        
        if (!string.IsNullOrEmpty(studentName))
        {
            sb.AppendLine($"  AND t1.XM LIKE '%{studentName}%'  -- 姓名");
        }
        
        sb.AppendLine("ORDER BY t1.SJ DESC");

        return sb.ToString();
    }

    /// <summary>
    /// 构建聚合统计SQL（GROUP BY 统计每个学生的进出次数）
    /// </summary>
    private string BuildAggregateQuery(string tableSuffix, DateTime startTime, DateTime endTime, int gateType, int? minCount, string? studentId, string? studentName)
    {
        var sb = new StringBuilder();

        sb.AppendLine("SELECT");
        sb.AppendLine("    t1.XGH AS '学工号',");
        sb.AppendLine("    t1.XM AS '姓名',");
        sb.AppendLine("    COUNT(*) AS '进出总次数',");
        sb.AppendLine("    MIN(DATE_FORMAT(t1.SJ, '%Y-%m-%d %H:%i')) AS '最早时间',");
        sb.AppendLine("    MAX(DATE_FORMAT(t1.SJ, '%Y-%m-%d %H:%i')) AS '最后时间',");
        sb.AppendLine("    GROUP_CONCAT(DISTINCT t2.GateName ORDER BY t1.SJ SEPARATOR ', ') AS '使用的闸机',");
        sb.AppendLine("    COUNT(DISTINCT DATE(t1.SJ)) AS '活跃天数'");
        sb.AppendLine($"FROM tblgateinformation_{tableSuffix} t1");
        sb.AppendLine("INNER JOIN TblGateDetail t2");
        sb.AppendLine("    ON t1.ZJID = t2.GateCode");
        sb.AppendLine($"WHERE t2.GateType = {gateType}  -- 闸机类型");
        sb.AppendLine($"  AND t1.SJ >= '{startTime:yyyy-MM-dd HH:mm:ss}'  -- 开始时间");
        sb.AppendLine($"  AND t1.SJ < '{endTime:yyyy-MM-dd HH:mm:ss}'  -- 结束时间");
        
        // 可选筛选条件
        if (!string.IsNullOrEmpty(studentId))
        {
            sb.AppendLine($"  AND t1.XGH = '{studentId}'");
        }
        
        if (!string.IsNullOrEmpty(studentName))
        {
            sb.AppendLine($"  AND t1.XM LIKE '%{studentName}%'");
        }
        
        sb.AppendLine("GROUP BY t1.XGH, t1.XM");
        
        // 最小次数阈值
        if (minCount.HasValue && minCount.Value > 0)
        {
            sb.AppendLine($"HAVING COUNT(*) > {minCount.Value}  -- 超过{minCount.Value}次");
        }
        
        sb.AppendLine("ORDER BY COUNT(*) DESC");

        return sb.ToString();
    }
}

